using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Infrastructure.CmsDbContext;
using Microsoft.EntityFrameworkCore;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 安全日志应用服务实现
    /// 提供安全事件日志的业务逻辑操作
    /// </summary>
    public class SecurityLogAppService : ISecurityLogAppService
    {
        private readonly LowCodeDbContext _dbContext;
        private readonly ILogger<SecurityLogAppService> _logger;

        public SecurityLogAppService(
            LowCodeDbContext dbContext,
            ILogger<SecurityLogAppService> logger)
        {
            _dbContext = dbContext;
            _logger = logger;
        }

        public async Task<long> LogSecurityEventAsync(
            string eventType,
            string message,
            string? threatLevel = null,
            string? userId = null,
            string? ipAddress = null,
            string? userAgent = null,
            string? tenantId = null,
            string? correlationId = null,
            bool isBlocked = false,
            Dictionary<string, object>? additionalData = null)
        {
            try
            {
                var securityLog = new SecurityLog
                {
                    TraceId = Guid.NewGuid().ToString(),
                    LogLevel = DetermineLogLevel(threatLevel),
                    Message = message,
                    Timestamp = DateTime.UtcNow,
                    UserId = userId,
                    RequestPath = GetValueFromAdditionalData(additionalData, "RequestPath"),
                    HttpMethod = GetValueFromAdditionalData(additionalData, "HttpMethod"),
                    StatusCode = GetIntValueFromAdditionalData(additionalData, "StatusCode"),
                    IpAddress = ipAddress,
                    UserAgent = userAgent,
                    SecurityEventType = eventType,
                    ThreatLevel = threatLevel ?? "Low",
                    AttackType = GetValueFromAdditionalData(additionalData, "AttackType"),
                    IsBlocked = isBlocked,
                    BlockReason = isBlocked ? GetValueFromAdditionalData(additionalData, "BlockReason") : null,
                    RiskScore = GetIntValueFromAdditionalData(additionalData, "RiskScore") ?? CalculateRiskScore(threatLevel, isBlocked),
                    GeolocationInfo = GetValueFromAdditionalData(additionalData, "GeolocationInfo"),
                    DeviceInfo = GetValueFromAdditionalData(additionalData, "DeviceInfo"),
                    TenantId = tenantId ?? string.Empty,
                    CorrelationId = correlationId,
                    AdditionalData = additionalData != null ? System.Text.Json.JsonSerializer.Serialize(additionalData) : null,
                    CreatedAt = DateTime.UtcNow
                };

                _dbContext.SecurityLogs.Add(securityLog);
                await _dbContext.SaveChangesAsync();

                return securityLog.Id;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录安全事件日志时发生错误");
                return 0;
            }
        }

        public async Task<long> LogLoginSecurityEventAsync(LoginSecurityContext context)
        {
            try
            {
                var securityLog = new SecurityLog
                {
                    TraceId = Guid.NewGuid().ToString(),
                    LogLevel = context.LoginResult == "Failed" ? "Warning" : "Info",
                    Message = $"用户登录{context.LoginResult}: {context.UserName ?? context.UserId}",
                    Timestamp = DateTime.UtcNow,
                    UserId = context.UserId,
                    IpAddress = context.IpAddress,
                    UserAgent = context.UserAgent,
                    SecurityEventType = context.LoginResult == "Success" ? "LoginSuccess" : "LoginFailure",
                    ThreatLevel = context.IsSuspiciousActivity ? "High" : "Low",
                    IsBlocked = context.LoginResult == "Blocked",
                    BlockReason = context.FailureReason,
                    RiskScore = context.IsSuspiciousActivity ? 80 : (context.IsNewDevice ? 40 : 10),
                    GeolocationInfo = context.GeolocationInfo,
                    DeviceInfo = context.DeviceInfo,
                    TenantId = context.TenantId ?? string.Empty,
                    CorrelationId = context.CorrelationId,
                    AdditionalData = context.AdditionalData != null ? System.Text.Json.JsonSerializer.Serialize(context.AdditionalData) : null,
                    CreatedAt = DateTime.UtcNow
                };

                _dbContext.SecurityLogs.Add(securityLog);
                await _dbContext.SaveChangesAsync();

                return securityLog.Id;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录登录安全事件日志时发生错误");
                return 0;
            }
        }

        public async Task<long> LogPermissionViolationAsync(PermissionViolationContext context)
        {
            try
            {
                var securityLog = new SecurityLog
                {
                    TraceId = Guid.NewGuid().ToString(),
                    LogLevel = "Warning",
                    Message = $"权限违规: 用户 {context.UserName ?? context.UserId} 尝试访问 {context.AccessedResource} 但缺少权限 {context.RequiredPermission}",
                    Timestamp = DateTime.UtcNow,
                    UserId = context.UserId,
                    RequestPath = context.RequestPath,
                    HttpMethod = context.HttpMethod,
                    StatusCode = 403,
                    IpAddress = context.IpAddress,
                    UserAgent = context.UserAgent,
                    SecurityEventType = "PermissionViolation",
                    ThreatLevel = "Medium",
                    AttackType = context.ViolationType,
                    IsBlocked = true,
                    BlockReason = $"缺少权限: {context.RequiredPermission}",
                    RiskScore = context.RiskScore > 0 ? context.RiskScore : 50,
                    TenantId = context.TenantId ?? string.Empty,
                    CorrelationId = context.CorrelationId,
                    AdditionalData = context.AdditionalData != null ? System.Text.Json.JsonSerializer.Serialize(context.AdditionalData) : null,
                    CreatedAt = DateTime.UtcNow
                };

                _dbContext.SecurityLogs.Add(securityLog);
                await _dbContext.SaveChangesAsync();

                return securityLog.Id;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录权限违规事件日志时发生错误");
                return 0;
            }
        }

        public async Task<long> LogAttackDetectionAsync(AttackDetectionContext context)
        {
            try
            {
                var securityLog = new SecurityLog
                {
                    TraceId = Guid.NewGuid().ToString(),
                    LogLevel = context.ThreatLevel == "Critical" ? "Error" : "Warning",
                    Message = $"检测到攻击: {context.AttackType} 来自 {context.IpAddress}",
                    Timestamp = DateTime.UtcNow,
                    UserId = context.UserId,
                    RequestPath = context.RequestPath,
                    HttpMethod = context.HttpMethod,
                    IpAddress = context.IpAddress,
                    UserAgent = context.UserAgent,
                    SecurityEventType = "AttackDetection",
                    ThreatLevel = context.ThreatLevel,
                    AttackType = context.AttackType,
                    IsBlocked = context.IsBlocked,
                    BlockReason = context.BlockReason,
                    RiskScore = context.RiskScore,
                    GeolocationInfo = context.GeolocationInfo,
                    TenantId = context.TenantId ?? string.Empty,
                    CorrelationId = context.CorrelationId,
                    AdditionalData = context.AttackData != null ? System.Text.Json.JsonSerializer.Serialize(context.AttackData) : null,
                    CreatedAt = DateTime.UtcNow
                };

                _dbContext.SecurityLogs.Add(securityLog);
                await _dbContext.SaveChangesAsync();

                return securityLog.Id;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录攻击检测事件日志时发生错误");
                return 0;
            }
        }

        public async Task<SecurityLogDto?> GetSecurityLogAsync(long id)
        {
            try
            {
                var securityLog = await _dbContext.SecurityLogs.FindAsync(id);
                if (securityLog == null) return null;

                return MapToDto(securityLog);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取安全日志时发生错误，ID: {Id}", id);
                return null;
            }
        }

        public async Task<(List<SecurityLogDto> Items, int TotalCount)> GetSecurityLogsAsync(
            string? tenantId = null,
            string? eventType = null,
            string? threatLevel = null,
            string? userId = null,
            string? ipAddress = null,
            DateTime? startTime = null,
            DateTime? endTime = null,
            bool? isBlocked = null,
            int pageIndex = 1,
            int pageSize = 20)
        {
            try
            {
                var query = _dbContext.SecurityLogs.AsQueryable();

                if (!string.IsNullOrEmpty(tenantId))
                    query = query.Where(x => x.TenantId == tenantId);

                if (!string.IsNullOrEmpty(eventType))
                    query = query.Where(x => x.SecurityEventType == eventType);

                if (!string.IsNullOrEmpty(threatLevel))
                    query = query.Where(x => x.ThreatLevel == threatLevel);

                if (!string.IsNullOrEmpty(userId))
                    query = query.Where(x => x.UserId == userId);

                if (!string.IsNullOrEmpty(ipAddress))
                    query = query.Where(x => x.IpAddress == ipAddress);

                if (isBlocked.HasValue)
                    query = query.Where(x => x.IsBlocked == isBlocked.Value);

                if (startTime.HasValue)
                    query = query.Where(x => x.Timestamp >= startTime.Value);

                if (endTime.HasValue)
                    query = query.Where(x => x.Timestamp <= endTime.Value);

                var totalCount = await query.CountAsync();

                var items = await query
                    .OrderByDescending(x => x.Timestamp)
                    .Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .Select(x => MapToDto(x))
                    .ToListAsync();

                return (items, totalCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取安全日志列表时发生错误");
                return (new List<SecurityLogDto>(), 0);
            }
        }

        public async Task<SecurityThreatStatistics> GetSecurityThreatStatisticsAsync(
            string? tenantId = null,
            DateTime? startTime = null,
            DateTime? endTime = null)
        {
            try
            {
                var query = _dbContext.SecurityLogs.AsQueryable();

                if (!string.IsNullOrEmpty(tenantId))
                    query = query.Where(x => x.TenantId == tenantId);

                if (startTime.HasValue)
                    query = query.Where(x => x.Timestamp >= startTime.Value);

                if (endTime.HasValue)
                    query = query.Where(x => x.Timestamp <= endTime.Value);

                var statistics = new SecurityThreatStatistics
                {
                    TotalSecurityEvents = await query.CountAsync(),
                    CriticalThreats = await query.Where(x => x.ThreatLevel == "Critical").CountAsync(),
                    HighThreats = await query.Where(x => x.ThreatLevel == "High").CountAsync(),
                    MediumThreats = await query.Where(x => x.ThreatLevel == "Medium").CountAsync(),
                    LowThreats = await query.Where(x => x.ThreatLevel == "Low").CountAsync(),
                    BlockedEvents = await query.Where(x => x.IsBlocked == true).CountAsync()
                };

                // 威胁类型统计
                statistics.ThreatTypeCount = await query
                    .GroupBy(x => x.SecurityEventType)
                    .Select(g => new { Type = g.Key ?? "Unknown", Count = g.Count() })
                    .ToDictionaryAsync(x => x.Type, x => x.Count);

                // 攻击类型统计
                statistics.AttackTypeCount = await query
                    .Where(x => !string.IsNullOrEmpty(x.AttackType))
                    .GroupBy(x => x.AttackType)
                    .Select(g => new { Type = g.Key!, Count = g.Count() })
                    .ToDictionaryAsync(x => x.Type, x => x.Count);

                // 按小时统计威胁
                if (startTime.HasValue && endTime.HasValue)
                {
                    statistics.ThreatsByHour = await query
                        .GroupBy(x => x.Timestamp.Hour)
                        .Select(g => new { Hour = g.Key.ToString(), Count = g.Count() })
                        .ToDictionaryAsync(x => x.Hour, x => x.Count);
                }

                // 威胁最多的IP地址
                statistics.TopThreatIps = await query
                    .Where(x => !string.IsNullOrEmpty(x.IpAddress))
                    .GroupBy(x => x.IpAddress)
                    .OrderByDescending(g => g.Count())
                    .Take(10)
                    .Select(g => g.Key!)
                    .ToListAsync();

                // 最常被攻击的路径
                statistics.TopTargetPaths = await query
                    .Where(x => !string.IsNullOrEmpty(x.RequestPath))
                    .GroupBy(x => x.RequestPath)
                    .OrderByDescending(g => g.Count())
                    .Take(10)
                    .Select(g => g.Key!)
                    .ToListAsync();

                return statistics;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取安全威胁统计时发生错误");
                return new SecurityThreatStatistics();
            }
        }

        public async Task<IpRiskAssessment> GetIpRiskAssessmentAsync(string ipAddress, string? tenantId = null)
        {
            try
            {
                var query = _dbContext.SecurityLogs.Where(x => x.IpAddress == ipAddress);

                if (!string.IsNullOrEmpty(tenantId))
                    query = query.Where(x => x.TenantId == tenantId);

                var assessment = new IpRiskAssessment
                {
                    IpAddress = ipAddress,
                    TotalEvents = await query.CountAsync(),
                    BlockedEvents = await query.Where(x => x.IsBlocked == true).CountAsync(),
                    LoginFailures = await query.Where(x => x.SecurityEventType == "LoginFailure").CountAsync(),
                    PermissionViolations = await query.Where(x => x.SecurityEventType == "PermissionViolation").CountAsync(),
                    AttackAttempts = await query.Where(x => x.SecurityEventType == "AttackDetection").CountAsync()
                };

                if (assessment.TotalEvents > 0)
                {
                    assessment.LastActivity = await query.MaxAsync(x => x.Timestamp);
                    
                    // 计算风险评分
                    assessment.RiskScore = CalculateIpRiskScore(assessment);
                    assessment.RiskLevel = DetermineRiskLevel(assessment.RiskScore);

                    // 获取最近的攻击类型
                    assessment.RecentAttackTypes = await query
                        .Where(x => !string.IsNullOrEmpty(x.AttackType))
                        .OrderByDescending(x => x.Timestamp)
                        .Take(5)
                        .Select(x => x.AttackType!)
                        .Distinct()
                        .ToListAsync();
                }

                return assessment;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取IP风险评估时发生错误，IP: {IpAddress}", ipAddress);
                return new IpRiskAssessment { IpAddress = ipAddress };
            }
        }

        public async Task<UserSecurityStatistics> GetUserSecurityStatisticsAsync(
            string userId,
            string? tenantId = null,
            DateTime? startTime = null,
            DateTime? endTime = null)
        {
            try
            {
                var query = _dbContext.SecurityLogs.Where(x => x.UserId == userId);

                if (!string.IsNullOrEmpty(tenantId))
                    query = query.Where(x => x.TenantId == tenantId);

                if (startTime.HasValue)
                    query = query.Where(x => x.Timestamp >= startTime.Value);

                if (endTime.HasValue)
                    query = query.Where(x => x.Timestamp <= endTime.Value);

                var statistics = new UserSecurityStatistics
                {
                    UserId = userId,
                    TotalSecurityEvents = await query.CountAsync(),
                    LoginEvents = await query.Where(x => x.SecurityEventType!.Contains("Login")).CountAsync(),
                    PermissionViolations = await query.Where(x => x.SecurityEventType == "PermissionViolation").CountAsync(),
                    FailedLogins = await query.Where(x => x.SecurityEventType == "LoginFailure").CountAsync(),
                    SuspiciousActivities = await query.Where(x => x.ThreatLevel == "High" || x.ThreatLevel == "Critical").CountAsync()
                };

                // 事件类型统计
                statistics.EventTypeCount = await query
                    .GroupBy(x => x.SecurityEventType)
                    .Select(g => new { Type = g.Key ?? "Unknown", Count = g.Count() })
                    .ToDictionaryAsync(x => x.Type, x => x.Count);

                // IP地址统计
                statistics.IpAddressCount = await query
                    .Where(x => !string.IsNullOrEmpty(x.IpAddress))
                    .GroupBy(x => x.IpAddress)
                    .Select(g => new { IpAddress = g.Key!, Count = g.Count() })
                    .ToDictionaryAsync(x => x.IpAddress, x => x.Count);

                if (statistics.TotalSecurityEvents > 0)
                {
                    var lastLoginQuery = query.Where(x => x.SecurityEventType == "LoginSuccess").OrderByDescending(x => x.Timestamp);
                    if (await lastLoginQuery.AnyAsync())
                    {
                        var lastLogin = await lastLoginQuery.FirstAsync();
                        statistics.LastLoginTime = lastLogin.Timestamp;
                        statistics.LastLoginIp = lastLogin.IpAddress;
                    }

                    // 计算用户风险评分
                    statistics.RiskScore = CalculateUserRiskScore(statistics);
                    statistics.HasSuspiciousPatterns = statistics.SuspiciousActivities > 0 || statistics.PermissionViolations > 5;
                }

                return statistics;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取用户安全统计时发生错误，UserId: {UserId}", userId);
                return new UserSecurityStatistics { UserId = userId };
            }
        }

        public async Task<int> LogBatchSecurityEventsAsync(IEnumerable<SecurityEventContext> events)
        {
            try
            {
                var securityLogs = events.Select(eventContext => new SecurityLog
                {
                    TraceId = Guid.NewGuid().ToString(),
                    LogLevel = DetermineLogLevel(eventContext.ThreatLevel),
                    Message = eventContext.Message,
                    Timestamp = eventContext.Timestamp,
                    UserId = eventContext.UserId,
                    RequestPath = eventContext.RequestPath,
                    HttpMethod = eventContext.HttpMethod,
                    IpAddress = eventContext.IpAddress,
                    UserAgent = eventContext.UserAgent,
                    SecurityEventType = eventContext.EventType,
                    ThreatLevel = eventContext.ThreatLevel ?? "Low",
                    IsBlocked = eventContext.IsBlocked,
                    BlockReason = eventContext.BlockReason,
                    RiskScore = eventContext.RiskScore ?? CalculateRiskScore(eventContext.ThreatLevel, eventContext.IsBlocked),
                    TenantId = eventContext.TenantId ?? string.Empty,
                    CorrelationId = eventContext.CorrelationId,
                    AdditionalData = eventContext.AdditionalData != null ? System.Text.Json.JsonSerializer.Serialize(eventContext.AdditionalData) : null,
                    CreatedAt = DateTime.UtcNow
                }).ToList();

                _dbContext.SecurityLogs.AddRange(securityLogs);
                await _dbContext.SaveChangesAsync();

                return securityLogs.Count;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量记录安全事件日志时发生错误");
                return 0;
            }
        }

        #region 私有辅助方法

        private string DetermineLogLevel(string? threatLevel)
        {
            return threatLevel switch
            {
                "Critical" => "Error",
                "High" => "Warning",
                "Medium" => "Warning",
                "Low" or null => "Info",
                _ => "Info"
            };
        }

        private int CalculateRiskScore(string? threatLevel, bool isBlocked)
        {
            var score = threatLevel switch
            {
                "Critical" => 90,
                "High" => 70,
                "Medium" => 50,
                "Low" or null => 20,
                _ => 20
            };

            return isBlocked ? score + 10 : score;
        }

        private int CalculateIpRiskScore(IpRiskAssessment assessment)
        {
            var score = 0;
            score += assessment.AttackAttempts * 20;
            score += assessment.LoginFailures * 10;
            score += assessment.PermissionViolations * 15;
            score += assessment.BlockedEvents * 5;

            return Math.Min(score, 100);
        }

        private string DetermineRiskLevel(int riskScore)
        {
            return riskScore switch
            {
                >= 80 => "Critical",
                >= 60 => "High",
                >= 40 => "Medium",
                _ => "Low"
            };
        }

        private int CalculateUserRiskScore(UserSecurityStatistics statistics)
        {
            var score = 0;
            score += statistics.SuspiciousActivities * 20;
            score += statistics.PermissionViolations * 15;
            score += statistics.FailedLogins * 5;

            return Math.Min(score, 100);
        }

        private string? GetValueFromAdditionalData(Dictionary<string, object>? additionalData, string key)
        {
            return additionalData?.TryGetValue(key, out var value) == true ? value?.ToString() : null;
        }

        private int? GetIntValueFromAdditionalData(Dictionary<string, object>? additionalData, string key)
        {
            if (additionalData?.TryGetValue(key, out var value) == true && value != null)
            {
                if (int.TryParse(value.ToString(), out var intValue))
                    return intValue;
            }
            return null;
        }

        private SecurityLogDto MapToDto(SecurityLog entity)
        {
            return new SecurityLogDto
            {
                Id = entity.Id,
                TraceId = entity.TraceId,
                LogLevel = entity.LogLevel,
                Message = entity.Message,
                Timestamp = entity.Timestamp,
                UserId = entity.UserId,
                RequestPath = entity.RequestPath,
                HttpMethod = entity.HttpMethod,
                StatusCode = entity.StatusCode,
                IpAddress = entity.IpAddress,
                UserAgent = entity.UserAgent,
                SecurityEventType = entity.SecurityEventType,
                ThreatLevel = entity.ThreatLevel,
                AttackType = entity.AttackType,
                IsBlocked = entity.IsBlocked ?? false,
                BlockReason = entity.BlockReason,
                RiskScore = entity.RiskScore,
                GeolocationInfo = entity.GeolocationInfo,
                DeviceInfo = entity.DeviceInfo,
                TenantId = entity.TenantId,
                CorrelationId = entity.CorrelationId,
                AdditionalData = entity.AdditionalData,
                CreatedAt = entity.CreatedAt ?? DateTime.UtcNow
            };
        }

        #endregion
    }
}
